package com.liyong.pullorder.sdk.sentinel;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.liyong.pullorder.sdk.autoconfigure.PullOrderSdkProperties;
import com.liyong.pullorder.sdk.dto.PlatformOrderResponse;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 葡萄味的萝卜
 * @date 2025/10/21 12:14
 * Sentinel流量控制配置
 * 核心作用：集成Sentinel实现限流降级，保障系统稳定性
 * 设计目标：防止异常流量冲击，实现多级fallback保护
 *
 * 保护能力：
 * - QPS限流：控制请求频率
 * - 并发控制：防止资源耗尽
 * - 降级策略：异常比例/异常数降级
 * - 系统保护：Load、CPU、RT等多维度
 *
 * 监控告警：对接公司告警平台，实时通知拉单异常
 */
@Slf4j
public class SentinelConfig {
    private final PullOrderSdkProperties properties;

    // 构造函数，参数传入Sentinel配置属性
    public SentinelConfig(PullOrderSdkProperties properties) {
        this.properties = properties;
    }

    /**
     * 初始化Sentinel规则
     * 执行时机：Bean初始化完成后自动执行
     * 作用：配置限流规则、降级规则等
     */
    @PostConstruct
    public void initSentinelRules() {
        if (!properties.getSentinel().isEnabled()) {
            log.info("Sentinel未启用，跳过规则初始化");
            return;
        }

        List<FlowRule> rules = new ArrayList<>();

        // 全局拉单限流规则
        FlowRule globalRule = new FlowRule();
        globalRule.setResource("pullOrderGlobal");
        globalRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        globalRule.setCount(properties.getSentinel().getQps());
        globalRule.setLimitApp("default");
        rules.add(globalRule);

        // 平台级限流规则（示例）
        properties.getPlatforms().forEach((platformCode, platformConfig) -> {
            FlowRule platformRule = new FlowRule();
            platformRule.setResource("pullOrder_" + platformCode);
            platformRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
            platformRule.setCount(50); // 每个平台默认50 QPS
            platformRule.setLimitApp("default");
            rules.add(platformRule);
        });

        FlowRuleManager.loadRules(rules);
        log.info("初始化Sentinel限流规则 - 全局QPS: {}, 平台数量: {}",
                properties.getSentinel().getQps(), properties.getPlatforms().size());
    }

    /**
     * 拉单限流降级处理
     * 作用：当拉单请求被限流时的fallback处理
     * 场景：系统过载、异常流量冲击
     */
    public static Object handlePullOrderBlock(BlockException ex) {
        String resourceName = ex.getRule().getResource();
        log.warn("拉单请求被限流 - 资源: {}, 规则: {}", resourceName, ex.getRule());

        // 记录限流指标
        MetricsCollector.recordBlockRequest(resourceName);

        // 返回限流响应
        return PlatformOrderResponse.failure(
                "RATE_LIMIT_EXCEEDED",
                "系统繁忙，请稍后重试"
        );
    }

    /**
     * 拉单异常降级处理
     * 作用：当拉单请求出现异常时的fallback处理
     * 场景：服务不可用、网络异常、系统错误
     */
    public static Object handlePullOrderFallback(String platformCode, Throwable ex) {
        log.error("拉单服务降级 - 平台: {}, 错误: {}", platformCode, ex.getMessage());

        // 记录降级指标
        MetricsCollector.recordFallback(platformCode, ex.getClass().getSimpleName());

        // 触发告警
        AlertManager.sendAlert("PULL_ORDER_FALLBACK",
                String.format("平台%s拉单服务降级，错误: %s", platformCode, ex.getMessage()));

        // 返回降级响应
        return PlatformOrderResponse.failure(
                "SERVICE_UNAVAILABLE",
                "服务暂时不可用，请稍后重试"
        );
    }

    /**
     * 监控指标收集器
     */
    private static class MetricsCollector {
        static void recordBlockRequest(String resourceName) {
            log.debug("记录限流指标 - 资源: {}", resourceName);
            // 对接公司监控平台
        }

        static void recordFallback(String platformCode, String errorType) {
            log.debug("记录降级指标 - 平台: {}, 错误类型: {}", platformCode, errorType);
            // 对接公司监控平台
        }
    }

    /**
     * 告警管理器
     */
    private static class AlertManager {
        static void sendAlert(String alertType, String message) {
            log.error("发送Sentinel告警 - 类型: {}, 内容: {}", alertType, message);
            // 对接公司告警平台，在拉单失败或数据异常时实时通知
        }
    }
}
